#include "mandarava/linux/tcpServer.hpp"

tcpServer :: tcpServer():m_fd__(-1),m_listen_addr__( 0 )
{

}

tcpServer :: tcpServer( const std::string& ip , uint16_t port ):m_fd__(-1) , m_listen_addr__( ip ), m_listen_port__(port)
{
#if USE_IPV6 == 1
	auto type = AF_INET6;
	struct sockaddr_in6 addr;
#else
	auto type = AF_INET;
	struct sockaddr_in addr;
#endif
	addr.sin_family = type;
	addr.sin_port = htons( port );
	inet_pton( type , ip.c_str() , addr.sin_addr );
	
	m_fd__ = socket( type , SOCK_STREAM, 0 );
	if( m_fd__ > 0 ){
		int rc = bind( m_fd__.load() , &addr , sizeof( addr ) );
		if( rc < 0 ){
			throw std::runtime_error( "" );
		}

#if USE_IPV6 == 1
		memcpy( &m_addr6__ , &addr , sizeof( addr ));
#else
		memcpy( &m_addr__ , &addr , sizeof( addr ));
#endif		
	}else{
		throw std::runtime_error( "" );
	}
}

tcpServer :: ~tcpServer()
{
	::close( m_fd__.load() );
}

bool tcpServer :: listen()
{
	bool ret = false;

	int rc = ::listen( m_fd__.load() , 100 );
	if( rc >= 0 ){
		return true;
	}
	
	return ret;
}

bool tcpServer :: listen( const std::string& ip , uint16_t port )
{
	m_listen_port__ = port;
	m_listen_addr__ = ip;
#if USE_IPV6 == 1
	auto type = AF_INET6;
	struct sockaddr_in6 addr;
#else
	auto type = AF_INET;
	struct sockaddr_in addr;
#endif
	addr.sin_family = type;
	addr.sin_port = htons( m_listen_port__.load() );
	inet_pton( type , m_listen_addr__.c_str() , addr.sin_addr );
	
	m_fd__ = socket( type , SOCK_STREAM, 0 );
	if( m_fd__ > 0 ){
		int rc = bind( m_fd__.load() , &addr , sizeof( addr ) );
		if( rc < 0 ){
			return false;
		}
	}else{
		return false;
	}

	int rc = ::listen( m_fd__.load() , 100 );
	if( rc >= 0 ){
#if USE_IPV6 == 1
		memcpy( &m_addr6__ , &addr , sizeof( addr ));
#else
		memcpy( &m_addr__ , &addr , sizeof( addr ));
#endif		
		return true;
	}

	return false;
}

void tcpServer :: onReadyRead( const uint8_t* data , size_t len )
{
	UNUSED( data );
	UNUSED( len );
	int sock = -1;
	socklen_t len;
	mandaravaIP_addr    addr;
	// 接受连接
	if ((sock = accept( m_fd__.load(), (struct sockaddr_in *)&addr, (socklen_t*)&len)) < 0) {
		mandaravaEvt evt = { mandaravaEvtID::EVT_ERROR , this , buff_t( 200 ) };
		std::string err( "连接请求失败" );
		memcpy( evt.m_buff.get() , err.c_str() , err.length() );
		evt.m_buff[ err.length() ] = '\0';
		evt.m_buff.dataLen( err.length() );
		cmd->send( evt );
        }
	// 创建新的连接对象，并将socket文件句柄和这个新的连接对象关联起来
	auto conn = std::make_shared< tcpConnection >( sock , addr , len , this );
	if( conn ){
		stConnItem  item = { addr };
		m_clients__.insert( std::make_paired( item , conn ) );

		// 通知外部应用有新的连接
		mandaravaEvt evt = { mandaravaEvtID::EVT_CONN , this , buff_t( 0 ) };
		std::string err( "连接请求失败" );
		memcpy( evt.m_buff.get() , err.c_str() , err.length() );
		evt.m_buff[ err.length() ] = '\0';
		evt.m_buff.dataLen( err.length() );
		cmd->send( evt , conn );
	}else{
		mandaravaEvt evt = { mandaravaEvtID::EVT_ERROR , this , buff_t( 200 ) };
		std::string err( "创建连接对象失败" );
		memcpy( evt.m_buff.get() , err.c_str() , err.length() );
		evt.m_buff[ err.length() ] = '\0';
		evt.m_buff.dataLen( err.length() );
		cmd->send( evt );
	}
}

